home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Kit PC World De Ampliacion De Windows 95
/
Kit PC World de ampliacion de Windows 95.iso
/
internet
/
sweeper
/
samples
/
olecon~1
/
framewrk
/
ctlmisc.cpp
< prev
next >
Wrap
Text File
|
1995-12-02
|
42KB
|
1,463 lines
//=--------------------------------------------------------------------------=
// ControlMisc.Cpp
//=--------------------------------------------------------------------------=
// Copyright 1995 Microsoft Corporation. All Rights Reserved.
//
// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
// ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
// PARTICULAR PURPOSE.
//=--------------------------------------------------------------------------=
//
// things that aren't elsewhere, such as property pages, and connection
// points.
//
#include "IPServer.H"
#include "CtrlObj.H"
#include "CtlHelp.H"
#include "Globals.H"
#include "StdEnum.H"
#include "Util.H"
#include <stdarg.h>
// for ASSERT and FAIL
//
SZTHISFILE
// this is used in our window proc so that we can find out who was last created
//
static COleControl *s_pLastControlCreated;
//=--------------------------------------------------------------------------=
// COleControl::COleControl
//=--------------------------------------------------------------------------=
// constructor
//
// Parameters:
// IUnknown * - [in] controlling Unknown
// int - [in] type of primary dispatch interface OBJECT_TYPE_*
// void * - [in] pointer to entire object
//
// Notes:
//
COleControl::COleControl
(
IUnknown *pUnkOuter,
int iPrimaryDispatch,
void *pMainInterface
)
: CAutomationObject(pUnkOuter, iPrimaryDispatch, pMainInterface),
m_cpEvents(SINK_TYPE_EVENT),
m_cpPropNotify(SINK_TYPE_PROPNOTIFY)
{
// initialize all our variables -- we decided against using a memory-zeroing
// memory allocator, so we sort of have to do this work now ...
//
m_nFreezeEvents = 0;
m_pClientSite = NULL;
m_pControlSite = NULL;
m_pInPlaceSite = NULL;
m_pInPlaceFrame = NULL;
m_pInPlaceUIWindow = NULL;
// certain hosts don't like 0,0 as your initial size, so we're going to set
// our initial size to 100,50 [so it's at least sort of visible on the screen]
//
m_Size.cx = 100;
m_Size.cy = 50;
m_hwnd = NULL;
m_hwndParent = NULL;
m_hwndReflect = NULL;
m_fHostReflects = TRUE;
m_fCheckedReflecting = FALSE;
m_dwWindowStyle = 0;
m_dwWindowExStyle = 0;
m_szWindowTitle = NULL;
m_cAccel = 0;
m_hAccel = NULL;
m_nFreezeEvents = 0;
m_pSimpleFrameSite = NULL;
m_pOleAdviseHolder = NULL;
m_pViewAdviseSink = NULL;
m_pDispAmbient = NULL;
m_fDirty = FALSE;
m_fModeFlagValid = FALSE;
m_fInPlaceActive = FALSE;
m_fInPlaceVisible = FALSE;
m_fUIActive = FALSE;
m_fSaveSucceeded = FALSE;
m_fViewAdvisePrimeFirst = FALSE;
m_fViewAdviseOnlyOnce = FALSE;
m_fRunMode = FALSE;
}
//=--------------------------------------------------------------------------=
// COleControl::~COleControl
//=--------------------------------------------------------------------------=
// "We are all of us resigned to death; it's life we aren't resigned to."
// - Graham Greene (1904-91)
//
// Notes:
//
COleControl::~COleControl()
{
// if we've still got a window, go and kill it now.
//
if (m_hwnd) {
// so our window proc doesn't crash.
//
SetWindowLong(m_hwnd, GWL_USERDATA, 0xFFFFFFFF);
DestroyWindow(m_hwnd);
}
if (m_hwndReflect) {
SetWindowLong(m_hwndReflect, GWL_USERDATA, 0);
DestroyWindow(m_hwndReflect);
}
// clean up all the pointers we're holding around.
//
RELEASE_OBJECT(m_pClientSite);
RELEASE_OBJECT(m_pControlSite);
RELEASE_OBJECT(m_pInPlaceSite);
RELEASE_OBJECT(m_pInPlaceFrame);
RELEASE_OBJECT(m_pInPlaceUIWindow);
RELEASE_OBJECT(m_pSimpleFrameSite);
RELEASE_OBJECT(m_pOleAdviseHolder);
RELEASE_OBJECT(m_pViewAdviseSink);
RELEASE_OBJECT(m_pDispAmbient);
}
#ifndef DEBUG
#pragma optimize("t", on)
#endif // DEBUG
//=--------------------------------------------------------------------------=
// COleControl::InternalQueryInterface
//=--------------------------------------------------------------------------=
// derived-controls should delegate back to this when they decide to support
// additional interfaces
//
// Parameters:
// REFIID - [in] interface they want
// void ** - [out] where they want to put the resulting object ptr.
//
// Output:
// HRESULT - S_OK, E_NOINTERFACE
//
// Notes:
// - NOTE: this function is speed critical!!!!
//
HRESULT COleControl::InternalQueryInterface
(
REFIID riid,
void **ppvObjOut
)
{
switch (riid.Data1) {
// private interface for prop page support
case Data1_IControlPrv:
if(DO_GUIDS_MATCH(riid, IID_IControlPrv)) {
*ppvObjOut = (void *)this;
ExternalAddRef();
return S_OK;
}
goto NoInterface;
QI_INHERITS(this, IOleControl);
QI_INHERITS(this, IOleObject);
QI_INHERITS((IPersistStorage *)this, IPersist);
QI_INHERITS(this, IPersistStreamInit);
QI_INHERITS(this, IOleInPlaceObject);
QI_INHERITS((IOleInPlaceActiveObject *)this, IOleWindow);
QI_INHERITS(this, IOleInPlaceActiveObject);
QI_INHERITS(this, IViewObject);
QI_INHERITS(this, IViewObject2);
QI_INHERITS(this, IConnectionPointContainer);
QI_INHERITS(this, ISpecifyPropertyPages);
QI_INHERITS(this, IPersistStorage);
QI_INHERITS(this, IPersistPropertyBag);
QI_INHERITS(this, IProvideClassInfo);
default:
goto NoInterface;
}
// we like the interface, so addref and return
//
((IUnknown *)(*ppvObjOut))->AddRef();
return S_OK;
NoInterface:
// delegate to super-class for automation interfaces, etc ...
//
return CAutomationObject::InternalQueryInterface(riid, ppvObjOut);
}
#ifndef DEBUG
#pragma optimize("s", on)
#endif // DEBUG
//=--------------------------------------------------------------------------=
// COleControl::FindConnectionPoint [IConnectionPointContainer]
//=--------------------------------------------------------------------------=
// given an IID, find a connection point sink for it.
//
// Parameters:
// REFIID - [in] interfaces they want
// IConnectionPoint ** - [out] where the cp should go
//
// Output:
// HRESULT
//
// Notes:
//
STDMETHODIMP COleControl::FindConnectionPoint
(
REFIID riid,
IConnectionPoint **ppConnectionPoint
)
{
CHECK_POINTER(ppConnectionPoint);
// we support the event interface, and IDispatch for it, and we also
// support IPropertyNotifySink.
//
if (DO_GUIDS_MATCH(riid, EVENTIIDOFCONTROL(m_ObjectType)) || DO_GUIDS_MATCH(riid, IID_IDispatch))
*ppConnectionPoint = &m_cpEvents;
else if (DO_GUIDS_MATCH(riid, IID_IPropertyNotifySink))
*ppConnectionPoint = &m_cpPropNotify;
else
return E_NOINTERFACE;
// generic post-processing.
//
(*ppConnectionPoint)->AddRef();
return S_OK;
}
//=--------------------------------------------------------------------------=
// COleControl::EnumConnectionPoints [IConnectionPointContainer]
//=--------------------------------------------------------------------------=
// creates an enumerator for connection points.
//
// Parameters:
// IEnumConnectionPoints ** - [out]
//
// Output:
// HRESULT
//
// Notes:
//
STDMETHODIMP COleControl::EnumConnectionPoints
(
IEnumConnectionPoints **ppEnumConnectionPoints
)
{
IConnectionPoint **rgConnectionPoints;
CHECK_POINTER(ppEnumConnectionPoints);
// HeapAlloc an array of connection points [since our standard enum
// assumes this and HeapFree's it later ]
//
rgConnectionPoints = (IConnectionPoint **)HeapAlloc(g_hHeap, 0, sizeof(IConnectionPoint *) * 2);
RETURN_ON_NULLALLOC(rgConnectionPoints);
// we support the event interface for this dude as well as IPropertyNotifySink
//
rgConnectionPoints[0] = &m_cpEvents;
rgConnectionPoints[1] = &m_cpPropNotify;
*ppEnumConnectionPoints = (IEnumConnectionPoints *)(IEnumGeneric *) new CStandardEnum(IID_IEnumConnectionPoints,
2, sizeof(IConnectionPoint *), (void *)rgConnectionPoints,
CopyAndAddRefObject);
if (!*ppEnumConnectionPoints) {
HeapFree(g_hHeap, 0, rgConnectionPoints);
return E_OUTOFMEMORY;
}
return S_OK;
}
//=--------------------------------------------------------------------------=
// COleControl::GetPages [ISpecifyPropertyPages]
//=--------------------------------------------------------------------------=
// returns a counted array with the guids for our property pages.
//
// parameters:
// CAUUID * - [out] where to put the counted array.
//
// Output:
// HRESULT
//
// NOtes:
//
STDMETHODIMP COleControl::GetPages
(
CAUUID *pPages
)
{
const GUID **pElems;
void *pv;
WORD x;
// if there are no property pages, this is actually pretty easy.
//
if (!CPROPPAGESOFCONTROL(m_ObjectType)) {
pPages->cElems = 0;
pPages->pElems = NULL;
return S_OK;
}
// fill out the Counted array, using IMalloc'd memory.
//
pPages->cElems = CPROPPAGESOFCONTROL(m_ObjectType);
pv = CoTaskMemAlloc(sizeof(GUID) * (pPages->cElems));
RETURN_ON_NULLALLOC(pv);
pPages->pElems = (GUID *)pv;
// loop through our array of pages and get 'em.
//
pElems = PPROPPAGESOFCONTROL(m_ObjectType);
for (x = 0; x < pPages->cElems; x++)
pPages->pElems[x] = *(pElems[x]);
return S_OK;
}
//=--------------------------------------------------------------------------=
// COleControl::CConnectionPoint::m_pOleControl
//=--------------------------------------------------------------------------=
// returns a pointer to the control in which we are nested.
//
// Output:
// COleControl *
//
// Notes:
//
inline COleControl *COleControl::CConnectionPoint::m_pOleControl
(
void
)
{
return (COleControl *)((BYTE *)this - ((m_bType == SINK_TYPE_EVENT)
? offsetof(COleControl, m_cpEvents)
: offsetof(COleControl, m_cpPropNotify)));
}
//=--------------------------------------------------------------------------=
// COleControl::CConnectionPoint::QueryInterface
//=--------------------------------------------------------------------------=
// standard qi
//
// Parameters:
// REFIID - [in] interface they want
// void ** - [out] where they want to put the resulting object ptr.
//
// Output:
// HRESULT - S_OK, E_NOINTERFACE
//
// Notes:
//
STDMETHODIMP COleControl::CConnectionPoint::QueryInterface
(
REFIID riid,
void **ppvObjOut
)
{
if (DO_GUIDS_MATCH(riid, IID_IConnectionPoint) || DO_GUIDS_MATCH(riid, IID_IUnknown)) {
*ppvObjOut = (IConnectionPoint *)this;
AddRef();
return S_OK;
}
return E_NOINTERFACE;
}
//=--------------------------------------------------------------------------=
// COleControl::CConnectionPoint::AddRef
//=--------------------------------------------------------------------------=
//
// Output:
// ULONG - the new reference count
//
// Notes:
//
ULONG COleControl::CConnectionPoint::AddRef
(
void
)
{
return m_pOleControl()->ExternalAddRef();
}
//=--------------------------------------------------------------------------=
// COleControl::CConnectionPoint::Release
//=--------------------------------------------------------------------------=
//
// Output:
// ULONG - remaining refs
//
// Notes:
//
ULONG COleControl::CConnectionPoint::Release
(
void
)
{
return m_pOleControl()->ExternalRelease();
}
//=--------------------------------------------------------------------------=
// COleControl::CConnectionPoint::GetConnectionInterface
//=--------------------------------------------------------------------------=
// returns the interface we support connections on.
//
// Parameters:
// IID * - [out] interface we support.
//
// Output:
// HRESULT
//
// Notes:
//
STDMETHODIMP COleControl::CConnectionPoint::GetConnectionInterface
(
IID *piid
)
{
if (m_bType == SINK_TYPE_EVENT)
*piid = EVENTIIDOFCONTROL(m_pOleControl()->m_ObjectType);
else
*piid = IID_IPropertyNotifySink;
return S_OK;
}
//=--------------------------------------------------------------------------=
// COleControl::CConnectionPoint::GetConnectionPointContainer
//=--------------------------------------------------------------------------=
// returns the connection point container
//
// Parameters:
// IConnectionPointContainer **ppCPC
//
// Output:
// HRESULT
//
// Notes:
//
STDMETHODIMP COleControl::CConnectionPoint::GetConnectionPointContainer
(
IConnectionPointContainer **ppCPC
)
{
return m_pOleControl()->ExternalQueryInterface(IID_IConnectionPointContainer, (void **)ppCPC);
}
//=--------------------------------------------------------------------------=
// COleControl::CConnectiontPoint::Advise
//=--------------------------------------------------------------------------=
// someboyd wants to be advised when something happens.
//
// Parameters:
// IUnknown * - [in] guy who wants to be advised.
// DWORD * - [out] cookie
//
// Output:
// HRESULT
//
// Notes:
//
STDMETHODIMP COleControl::CConnectionPoint::Advise
(
IUnknown *pUnk,
DWORD *pdwCookie
)
{
IUnknown **rgUnkNew;
HRESULT hr;
void *pv;
int i = 0;
CHECK_POINTER(pdwCookie);
// first, make sure everybody's got what they thinks they got
//
if (m_bType == SINK_TYPE_EVENT) {
// CONSIDER: 12.95 -- this theoretically is broken -- if they do a find
// connection point on IDispatch, and they just happened to also support
// the Event IID, we'd advise on that. this is not awesome, but will
// prove entirely acceptable short term.
//
hr = pUnk->QueryInterface(EVENTIIDOFCONTROL(m_pOleControl()->m_ObjectType), &pv);
if (FAILED(hr))
hr = pUnk->QueryInterface(IID_IDispatch, &pv);
}
else
hr = pUnk->QueryInterface(IID_IPropertyNotifySink, &pv);
RETURN_ON_FAILURE(hr);
// we optimize the case where there is only one sink to not allocate
// any storage. turns out very rarely is there more than one.
//
switch (m_cSinks) {
case 0:
ASSERT(!m_rgSinks, "Doh! this should be null when there are no sinks");
m_rgSinks = (IUnknown **)pv;
break;
case 1:
// go ahead and do the initial allocation. we'll get 8 at a time
//
rgUnkNew = (IUnknown **)HeapAlloc(g_hHeap, 0, 8 * sizeof(IUnknown *));
RETURN_ON_NULLALLOC(rgUnkNew);
rgUnkNew[0] = (IUnknown *)m_rgSinks;
rgUnkNew[1] = (IUnknown *)pv;
m_rgSinks = rgUnkNew;
break;
default:
// if we're out of sinks, then we have to increase the size
// of the array
//
if (!(m_cSinks & 0x7)) {
rgUnkNew = (IUnknown **)HeapReAlloc(g_hHeap, 0, m_rgSinks, (m_cSinks + 8) * sizeof(IUnknown *));
RETURN_ON_NULLALLOC(rgUnkNew);
m_rgSinks = rgUnkNew;
} else
rgUnkNew = m_rgSinks;
rgUnkNew[m_cSinks + 1] = (IUnknown *)pv;
break;
}
*pdwCookie = (DWORD)pv;
m_cSinks++;
return S_OK;
}
//=--------------------------------------------------------------------------=
// COleControl::CConnectionPoint::Unadvise
//=--------------------------------------------------------------------------=
// they don't want to be told any more.
//
// Parameters:
// DWORD - [in] the cookie we gave 'em.
//
// Output:
// HRESULT
//
// Notes:
//
STDMETHODIMP COleControl::CConnectionPoint::Unadvise
(
DWORD dwCookie
)
{
IUnknown *pUnk;
int x;
if (!dwCookie)
return S_OK;
// see how many sinks we've currently got, and deal with things based
// on that.
//
switch (m_cSinks) {
case 1:
// it's the only sink. make sure the ptrs are the same, and
// then free things up
//
if ((DWORD)m_rgSinks != dwCookie)
return CONNECT_E_NOCONNECTION;
m_rgSinks = NULL;
break;
case 2:
// there are two sinks. go back down to one sink scenario
//
if ((DWORD)m_rgSinks[0] != dwCookie && (DWORD)m_rgSinks[1] != dwCookie)
return CONNECT_E_NOCONNECTION;
pUnk = ((DWORD)m_rgSinks[0] == dwCookie) ? m_rgSinks[1] : m_rgSinks[0];
HeapFree(g_hHeap, 0, m_rgSinks);
m_rgSinks = (IUnknown **)pUnk;
break;
default:
// there are more than two sinks. just clean up the hole we've
// got in our array now.
//
for (x = 0; x < m_cSinks; x++) {
if ((DWORD)m_rgSinks[x] == dwCookie)
break;
}
if (x == m_cSinks) return CONNECT_E_NOCONNECTION;
memcpy(&(m_rgSinks[x]), &(m_rgSinks[x + 1]), (m_cSinks - x) * sizeof(IUnknown *));
break;
}
// we're happy
//
((IUnknown *)dwCookie)->Release();
m_cSinks--;
return S_OK;
}
//=--------------------------------------------------------------------------=
// COleControl::CConnectionPoint::EnumConnections
//=--------------------------------------------------------------------------=
// enumerates all current connections
//
// Paramters:
// IEnumConnections ** - [out] new enumerator object
//
// Output:
// HRESULT
//
// NOtes:
//
STDMETHODIMP COleControl::CConnectionPoint::EnumConnections
(
IEnumConnections **ppEnumOut
)
{
CONNECTDATA *rgConnectData = NULL;
int i;
if (m_cSinks) {
// allocate some memory big enough to hold all of the sinks.
//
rgConnectData = (CONNECTDATA *)HeapAlloc(g_hHeap, 0, m_cSinks * sizeof(IUnknown *));
RETURN_ON_NULLALLOC(rgConnectData);
// fill in the array
//
if (m_cSinks == 1) {
rgConnectData[0].pUnk = (IUnknown *)m_rgSinks;
rgConnectData[0].dwCookie = (DWORD)m_rgSinks;
} else {
// loop through all available sinks.
//
for (i = 0; i < m_cSinks; i++) {
rgConnectData[i].pUnk = m_rgSinks[i];
rgConnectData[i].dwCookie = (DWORD)m_rgSinks[i];
}
}
}
// create yon enumerator object.
//
*ppEnumOut = (IEnumConnections *)(IEnumGeneric *)new CStandardEnum(IID_IEnumConnections,
m_cSinks, sizeof(CONNECTDATA), rgConnectData, CopyAndAddRefObject);
if (!*ppEnumOut) {
HeapFree(g_hHeap, 0, rgConnectData);
return E_OUTOFMEMORY;
}
return S_OK;
}
//=--------------------------------------------------------------------------=
// COleControl::CConnectionPoint::~CConnectionPoint
//=--------------------------------------------------------------------------=
// cleans up
//
// Notes:
//
COleControl::CConnectionPoint::~CConnectionPoint ()
{
int x;
// clean up some memory stuff
//
if (!m_cSinks)
return;
else if (m_cSinks == 1)
((IUnknown *)m_rgSinks)->Release();
else {
for (x = 0; x < m_cSinks; x++)
RELEASE_OBJECT(m_rgSinks[x]);
HeapFree(g_hHeap, 0, m_rgSinks);
}
}
//=--------------------------------------------------------------------------=
// COleControl::CConnectionPiont::DoInvoke
//=--------------------------------------------------------------------------=
// fires an event to all listening on our event interface.
//
// Parameters:
// DISPID - [in] event to fire.
// DISPPARAMS - [in]
//
// Notes:
//
void COleControl::CConnectionPoint::DoInvoke
(
DISPID dispid,
DISPPARAMS *pdispparams
)
{
int iConnection;
// if we don't have any sinks, then there's nothing to do. we intentionally
// ignore errors here.
//
if (m_cSinks == 0)
return;
else if (m_cSinks == 1)
((IDispatch *)m_rgSinks)->Invoke(dispid, IID_NULL, 0, DISPATCH_METHOD, pdispparams, NULL, NULL, NULL);
else
for (iConnection = 0; iConnection < m_cSinks; iConnection++)
((IDispatch *)m_rgSinks[iConnection])->Invoke(dispid, IID_NULL, 0, DISPATCH_METHOD, pdispparams, NULL, NULL, NULL);
}
//=--------------------------------------------------------------------------=
// COleControl::CConnectionPoint::DoOnChanged
//=--------------------------------------------------------------------------=
// fires the OnChanged event for IPropertyNotifySink listeners.
//
// Parameters:
// DISPID - [in] dude that changed.
//
// Output:
// none
//
// Notes:
//
void COleControl::CConnectionPoint::DoOnChanged
(
DISPID dispid
)
{
int iConnection;
// if we don't have any sinks, then there's nothing to do.
//
if (m_cSinks == 0)
return;
else if (m_cSinks == 1)
((IPropertyNotifySink *)m_rgSinks)->OnChanged(dispid);
else
for (iConnection = 0; iConnection < m_cSinks; iConnection++)
((IPropertyNotifySink *)m_rgSinks[iConnection])->OnChanged(dispid);
}
//=--------------------------------------------------------------------------=
// COleControl::CConnectionPoint::DoOnRequestEdit
//=--------------------------------------------------------------------------=
// fires the OnRequestEdit for IPropertyNotifySinkListeners
//
// Parameters:
// DISPID - [in] dispid user wants to change.
//
// Output:
// BOOL - false means you cant
//
// Notes:
//
BOOL COleControl::CConnectionPoint::DoOnRequestEdit
(
DISPID dispid
)
{
HRESULT hr;
int iConnection;
// if we don't have any sinks, then there's nothing to do.
//
if (m_cSinks == 0)
hr = S_OK;
else if (m_cSinks == 1)
hr =((IPropertyNotifySink *)m_rgSinks)->OnChanged(dispid);
else {
for (iConnection = 0; iConnection < m_cSinks; iConnection++) {
hr = ((IPropertyNotifySink *)m_rgSinks[iConnection])->OnChanged(dispid);
if (hr != S_OK) break;
}
}
return (hr == S_OK) ? TRUE : FALSE;
}
//=--------------------------------------------------------------------------=
// COleControl::CreateInPlaceWindow
//=--------------------------------------------------------------------------=
// creates the window with which we will be working.
// yay.
//
// Parameters:
// int - [in] left
// int - [in] top
//
// Output:
// HWND
//
// Notes:
//
HWND COleControl::CreateInPlaceWindow
(
int x,
int y
)
{
BOOL fVisible;
HRESULT hr;
DWORD dwWindowStyle;
// if we've already got a window, do nothing.
//
if (m_hwnd)
return m_hwnd;
// get the user to register the class if it's not already
// been done.
//
if (!CTLWNDCLASSREGISTERED(m_ObjectType)) {
if (!RegisterClassData())
return NULL;
else
CTLWNDCLASSREGISTERED(m_ObjectType) = TRUE;
}
// let the user set up things like the window title, the
// style, and anything else they feel interested in fiddling
// with.
//
BeforeCreateWindow();
dwWindowStyle = m_dwWindowStyle | WS_CHILD | WS_CLIPSIBLINGS;
// create window visible if parent hidden (common case)
// otherwise, create hidden, then shown. this is a little subtle, but
// it makes sense eventually.
//
if (!m_hwndParent)
m_hwndParent = GetParkingWindow();
fVisible = IsWindowVisible(m_hwndParent);
// This one kinda sucks -- if a control is subclassed, and we're in
// a host that doesn't support Message Reflecting, we have to create
// the user window in another window which will do all the reflecting.
// VERY blech. [don't however, bother in design mode]
//
if (SUBCLASSWNDPROCOFCONTROL(m_ObjectType) && (m_hwndParent != GetParkingWindow())) {
// determine if the host supports message reflecting.
//
if (!m_fCheckedReflecting) {
VARIANT_BOOL f;
hr = GetAmbientProperty(DISPID_AMBIENT_MESSAGEREFLECT, VT_BOOL, &f);
if (FAILED(hr) || !f)
m_fHostReflects = FALSE;
m_fCheckedReflecting = TRUE;
}
// if the host doesn't support reflecting, then we have to create
// an extra window around the control window, and then parent it
// off that.
//
if (!m_fHostReflects) {
ASSERT(m_hwndReflect == NULL, "Blood Spewing Maggots! Where'd this come from?");
m_hwndReflect = CreateReflectWindow(!fVisible, m_hwndParent, x, y, &m_Size);
if (!m_hwndReflect)
return NULL;
SetWindowLong(m_hwndReflect, GWL_USERDATA, (long)this);
dwWindowStyle |= WS_VISIBLE;
}
} else {
if (!fVisible)
dwWindowStyle |= WS_VISIBLE;
}
s_pLastControlCreated = this;
m_fCreatingWindow = TRUE;
// finally, go create the window, parenting it as appropriate.
//
m_hwnd = CreateWindowEx(m_dwWindowExStyle, WNDCLASSNAMEOFCONTROL(m_ObjectType),
m_szWindowTitle,
dwWindowStyle,
(m_hwndReflect) ? 0 : x,
(m_hwndReflect) ? 0 : y,
m_Size.cx, m_Size.cy,
(m_hwndReflect) ? m_hwndReflect : m_hwndParent,
NULL, g_hInstance, NULL);
m_fCreatingWindow = FALSE;
s_pLastControlCreated = NULL;
if (m_hwnd) {
// let the derived-control do something if they so desire
//
AfterCreateWindow();
// if we didn't create the window visible, show it now.
//
if (fVisible)
ShowWindow(GetOuterWindow(), SW_SHOW);
}
return m_hwnd;
}
//=--------------------------------------------------------------------------=
// COleControl::SetInPlaceParent [helper]
//=--------------------------------------------------------------------------=
// sets up the parent window for our control.
//
// Parameters:
// HWND - [in] new parent window
//
// Notes:
//
void COleControl::SetInPlaceParent
(
HWND hwndParent
)
{
if (m_hwndParent == hwndParent)
return;
m_hwndParent = hwndParent;
if (m_hwnd)
SetParent(GetOuterWindow(), hwndParent);
}
//=--------------------------------------------------------------------------=
// COleControl::ControlWindowProc
//=--------------------------------------------------------------------------=
// default window proc for an OLE Control. controls will have their own
// window proc called from this one, after some processing is done.
//
// Parameters:
// - see win32sdk docs.
//
// Notes:
//
LRESULT CALLBACK COleControl::ControlWindowProc
(
HWND hwnd,
UINT msg,
WPARAM wParam,
LPARAM lParam
)
{
COleControl *pCtl = ControlFromHwnd(hwnd);
HRESULT hr;
LRESULT lResult;
DWORD dwCookie;
// if the value isn't a positive value, then it's in some special
// state [creation or destruction] this is safe because under win32,
// the upper 2GB of an address space aren't available.
//
if ((LONG)pCtl == 0) {
pCtl = s_pLastControlCreated;
SetWindowLong(hwnd, GWL_USERDATA, (LONG)pCtl);
pCtl->m_hwnd = hwnd;
} else if ((ULONG)pCtl == 0xffffffff) {
return DefWindowProc(hwnd, msg, wParam, lParam);
}
// message preprocessing
//
if (pCtl->m_pSimpleFrameSite) {
hr = pCtl->m_pSimpleFrameSite->PreMessageFilter(hwnd, msg, wParam, lParam, &lResult, &dwCookie);
if (hr == S_FALSE) return lResult;
}
// for certain messages, do not call the user window proc. instead,
// we have something else we'd like to do.
//
switch (msg) {
case WM_PAINT:
{
// call the user's OnDraw routine.
//
PAINTSTRUCT ps;
RECT rc;
HDC hdc;
// if we're given an HDC, then use it
//
if (!wParam)
hdc = BeginPaint(hwnd, &ps);
else
hdc = (HDC)wParam;
GetClientRect(hwnd, &rc);
pCtl->OnDraw(hdc, (RECTL *)&rc, NULL, NULL);
if (!wParam)
EndPaint(hwnd, &ps);
}
break;
default:
// call the derived-control's window proc
//
lResult = pCtl->WindowProc(hwnd, msg, wParam, lParam);
break;
}
// message postprocessing
//
switch (msg) {
case WM_NCDESTROY:
// after this point, the window doesn't exist any more
//
pCtl->m_hwnd = NULL;
break;
case WM_SETFOCUS:
case WM_KILLFOCUS:
// give the control site focus notification
//
if (pCtl->m_fInPlaceActive && pCtl->m_pControlSite)
pCtl->m_pControlSite->OnFocus(msg == WM_SETFOCUS);
break;
case WM_SIZE:
// a change in size is a change in view
//
if (!pCtl->m_fCreatingWindow)
pCtl->ViewChanged();
break;
}
// lastly, simple frame postmessage processing
//
if (pCtl->m_pSimpleFrameSite)
pCtl->m_pSimpleFrameSite->PostMessageFilter(hwnd, msg, wParam, lParam, &lResult, dwCookie);
return lResult;
}
//=--------------------------------------------------------------------------=
// COleControl::ReflectWindowProc
//=--------------------------------------------------------------------------=
// reflects window messages on to the child window. very lame.
//
// Parameters and Output:
// - see win32 sdk docs
//
// Notes:
//
LRESULT CALLBACK COleControl::ReflectWindowProc
(
HWND hwnd,
UINT msg,
WPARAM wParam,
LPARAM lParam
)
{
COleControl *pCtl;
switch (msg) {
case WM_COMMAND:
case WM_NOTIFY:
case WM_CTLCOLORBTN:
case WM_CTLCOLORDLG:
case WM_CTLCOLOREDIT:
case WM_CTLCOLORLISTBOX:
case WM_CTLCOLORMSGBOX:
case WM_CTLCOLORSCROLLBAR:
case WM_CTLCOLORSTATIC:
case WM_DRAWITEM:
case WM_MEASUREITEM:
case WM_DELETEITEM:
case WM_VKEYTOITEM:
case WM_CHARTOITEM:
case WM_COMPAREITEM:
case WM_HSCROLL:
case WM_VSCROLL:
case WM_PARENTNOTIFY:
case WM_SETFOCUS:
case WM_SIZE:
pCtl = (COleControl *)GetWindowLong(hwnd, GWL_USERDATA);
if (pCtl)
return SendMessage(pCtl->m_hwnd, OCM__BASE + msg, wParam, lParam);
break;
}
return DefWindowProc(hwnd, msg, wParam, lParam);
}
//=--------------------------------------------------------------------------=
// COleControl::GetAmbientProperty [callable]
//=--------------------------------------------------------------------------=
// returns the value of an ambient property
//
// Parameters:
// DISPID - [in] property to get
// VARTYPE - [in] type of desired data
// void * - [out] where to put the data
//
// Output:
// BOOL - FALSE means didn't work.
//
// Notes:
//
BOOL COleControl::GetAmbientProperty
(
DISPID dispid,
VARTYPE vt,
void *pData
)
{
DISPPARAMS dispparams;
VARIANT v, v2;
HRESULT hr;
v.vt = VT_EMPTY;
v.lVal = 0;
v2.vt = VT_EMPTY;
v.lVal = 0;
// get a pointer to the source of ambient properties.
//
if (!m_pDispAmbient) {
if (m_pClientSite)
m_pClientSite->QueryInterface(IID_IDispatch, (void **)&m_pDispAmbient);
if (!m_pDispAmbient)
return FALSE;
}
// now go and get the property into a variant.
//
memset(&dispparams, 0, sizeof(DISPPARAMS));
hr = m_pDispAmbient->Invoke(dispid, IID_NULL, 0, DISPATCH_PROPERTYGET, &dispparams,
&v, NULL, NULL);
if (FAILED(hr)) return FALSE;
// we've got the variant, so now go an coerce it to the type that the user
// wants. if the types are the same, then this will copy the stuff to
// do appropriate ref counting ...
//
hr = VariantChangeType(&v2, &v, 0, vt);
if (FAILED(hr)) {
VariantClear(&v);
return FALSE;
}
// copy the data to where the user wants it
//
CopyMemory(pData, &(v2.lVal), g_rgcbDataTypeSize[vt]);
VariantClear(&v);
return TRUE;
}
//=--------------------------------------------------------------------------=
// COleControl::GetAmbientFont [callable]
//=--------------------------------------------------------------------------=
// gets the current font for the user.
//
// Parameters:
// IFont ** - [out] where to put the font.
//
// Output:
// BOOL - FALSE means couldn't get it.
//
// Notes:
//
BOOL COleControl::GetAmbientFont
(
IFont **ppFont
)
{
IDispatch *pFontDisp;
// we don't have to do much here except get the ambient property and QI
// it for the user.
//
*ppFont = NULL;
if (!GetAmbientProperty(DISPID_AMBIENT_FONT, VT_DISPATCH, &pFontDisp))
return FALSE;
pFontDisp->QueryInterface(IID_IFont, (void **)ppFont);
pFontDisp->Release();
return (*ppFont) ? TRUE : FALSE;
}
//=--------------------------------------------------------------------------=
// COleControl::DesignMode
//=--------------------------------------------------------------------------=
// returns TRUE if we're in Design mode.
//
// Output:
// BOOL - true is design mode, false is run mode
//
// Notes:
//
BOOL COleControl::DesignMode
(
void
)
{
// if we don't already know our run mode, go and get it. we'll assume
// it's true unless told otherwise [or if the operation fails ...]
//
if (!m_fModeFlagValid) {
m_fModeFlagValid = TRUE;
m_fRunMode = TRUE;
GetAmbientProperty(DISPID_AMBIENT_USERMODE, VT_BOOL, &m_fRunMode);
}
return !m_fRunMode;
}
//=--------------------------------------------------------------------------=
// COleControl::FireEvent
//=--------------------------------------------------------------------------=
// fires an event. handles arbitrary number of arguments.
//
// Parameters:
// EVENTINFO * - [in] struct that describes the event.
// ... - arguments to the event
//
// Output:
// none
//
// Notes:
// - use stdarg's va_* macros.
//
void __cdecl COleControl::FireEvent
(
EVENTINFO *pEventInfo,
...
)
{
va_list valist;
DISPPARAMS dispparams;
VARIANT rgvParameters[MAX_ARGS];
VARIANT *pv;
VARTYPE vt;
int iParameter;
int cbSize;
ASSERT(pEventInfo->cParameters <= MAX_ARGS, "Don't support more than MAX_ARGS params. sorry.");
va_start(valist, pEventInfo);
// copy the Parameters into the rgvParameters array. make sure we reverse
// them for automation
//
pv = &(rgvParameters[pEventInfo->cParameters - 1]);
for (iParameter = 0; iParameter < pEventInfo->cParameters; iParameter++) {
vt = pEventInfo->rgTypes[iParameter];
// if it's a by value variant, then just copy the whole
// dang thing
//
if (vt == VT_VARIANT)
*pv = va_arg(valist, VARIANT);
else {
// copy the vt and the data value.
//
pv->vt = vt;
if (vt & VT_BYREF)
cbSize = sizeof(void *);
else
cbSize = g_rgcbDataTypeSize[vt];
// small optimization -- we can copy 2/4 bytes over quite
// quickly.
//
if (cbSize == sizeof(short))
V_I2(pv) = va_arg(valist, short);
else if (cbSize == 4)
V_I4(pv) = va_arg(valist, long);
else {
// copy over 8 bytes
//
ASSERT(cbSize == 8, "D'oH! don't recognize the type!!");
V_CY(pv) = va_arg(valist, CURRENCY);
#if 0
// convert doubles back to floats
//
if (vt == VT_R4)
pv->fltVal = (float)pv->dblVal;
#endif // 0
}
}
pv--;
}
// fire the event
//
dispparams.rgvarg = rgvParameters;
dispparams.cArgs = pEventInfo->cParameters;
dispparams.rgdispidNamedArgs = NULL;
dispparams.cNamedArgs = 0;
m_cpEvents.DoInvoke(pEventInfo->dispid, &dispparams);
va_end(valist);
}
//=--------------------------------------------------------------------------=
// COleControl::AfterCreateWindow [overridable]
//=--------------------------------------------------------------------------=
// something the user can pay attention to
//
// Notes:
//
void COleControl::AfterCreateWindow
(
void
)
{
// do nothing
}
//=--------------------------------------------------------------------------=
// COleControl::InvalidateControl [callable]
//=--------------------------------------------------------------------------=
void COleControl::InvalidateControl(LPCRECT lpRect)
{
if (m_fInPlaceActive)
InvalidateRect(m_hwnd, lpRect, TRUE);
else
ViewChanged();
// CONSIDER: one might want to call pOleAdviseHolder->OnDataChanged() here
// if there was support for IDataObject
}
//=--------------------------------------------------------------------------=
// COleControl::SetControlSize [callable]
//=--------------------------------------------------------------------------=
// sets the control size. they'll give us the size in pixels. we've got to
// convert them back to HIMETRIC before passing them on!
//
// Parameters:
// SIZEL * - [in] new size
//
// Output:
// BOOL
//
// Notes:
//
BOOL COleControl::SetControlSize
(
SIZEL *pSize
)
{
HRESULT hr;
SIZEL slHiMetric;
PixelToHiMetric(pSize, &slHiMetric);
hr = SetExtent(DVASPECT_CONTENT, &slHiMetric);
return (FAILED(hr)) ? FALSE : TRUE;
}
//=--------------------------------------------------------------------------=
// COleControl::RecreateControlWindow [callable]
//=--------------------------------------------------------------------------=
// called by a [subclassed, typically] control to recreate it's control
// window.
//
// Parameters:
// none
//
// Output:
// HRESULT
//
// Notes:
// - NOTE: USE ME EXTREMELY SPARINGLY! THIS IS AN EXTREMELY EXPENSIVE
// OPERATION!
//
HRESULT COleControl::RecreateControlWindow
(
void
)
{
HRESULT hr;
// if we're in place active, then we have to deactivate, and reactivate
// ourselves with the new window ...
//
if (m_fInPlaceActive) {
hr = InPlaceDeactivate();
RETURN_ON_FAILURE(hr);
hr = InPlaceActivate((m_fUIActive) ? OLEIVERB_UIACTIVATE : OLEIVERB_INPLACEACTIVATE);
RETURN_ON_FAILURE(hr);
} else if (m_hwnd) {
DestroyWindow(m_hwnd);
m_hwnd = NULL;
if (m_hwndReflect) {
DestroyWindow(m_hwndReflect);
m_hwndReflect = NULL;
}
CreateInPlaceWindow(0, 0);
}
return m_hwnd ? S_OK : E_FAIL;
}
// from Globals.C
//
extern HINSTANCE g_hInstResources;
//=--------------------------------------------------------------------------=
// COleControl::GetResourceHandle [callable]
//=--------------------------------------------------------------------------=
// gets the HINSTANCE of the DLL where the control should get resources
// from. implemented in such a way to support satellite DLLs.
//
// Output:
// HINSTANCE
//
// Notes:
//
HINSTANCE COleControl::GetResourceHandle
(
void
)
{
if (!g_fSatelliteLocalization)
return g_hInstance;
// if we've already got it, then there's not all that much to do.
//
if (g_hInstResources)
return g_hInstResources;
// we'll get the ambient localeid from the host, and pass that on to the
// automation object.
//
if (!g_fHaveLocale)
if (!GetAmbientProperty(DISPID_AMBIENT_LOCALEID, VT_I4, &g_lcidLocale))
return NULL;
g_fHaveLocale = TRUE;
return ::GetResourceHandle();
}